package com.lizhaoshan.Interceptor;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.lizhaoshan.annotation.PassToken;
import com.lizhaoshan.annotation.EmployeeLoginToken;
import com.lizhaoshan.common.CustomException;
import com.lizhaoshan.common.Result;
import com.lizhaoshan.common.TokenHolder;
import com.lizhaoshan.constant.TokenConstant;
import com.lizhaoshan.dto.EmployeeDto;
import com.lizhaoshan.pojo.Employee;
import com.lizhaoshan.service.EmployeeService;
import com.lizhaoshan.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @program: reggie
 * @description: 拦截器
 * @author: lamour
 * @create: 2022-05-15 18:53
 **/
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {


    private RedisTemplate<Object, Object> redisTemplate;

    public AuthInterceptor() {
    }

    public AuthInterceptor(RedisTemplate<Object, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("employee拦截类preHandle执行，请求路径为："+request.getRequestURI());

        //获取请求头的token
        String token = request.getHeader("AuthorizationUser");

        if (StrUtil.isEmpty(token)) {
            log.info("未登录，无令牌");
            response.getWriter().write(JSON.toJSONString(Result.error("NOTLOGIN")));
            return false;
        }

        //通过token获取缓存中的信息，如果能获取到，说明这个token是正确的
        Object obj = redisTemplate.opsForValue().get(TokenConstant.USER_TOKEN_PREFIX + token);
        if (Objects.isNull(obj)) {
            log.info("用户名或密码错误");
            response.getWriter().write(JSON.toJSONString(Result.error("NOTLOGIN")));
            return false;
        }

        //将信息转换成employee对象
        Employee employee = JSON.parseObject((String) obj, Employee.class);
        log.info("**********将用户id存入线程,id为:"+employee.getId());
        TokenHolder.setCurrentId(employee.getId());

        return true;
    }


    // @Autowired
    // private EmployeeService employeeService;
    //
    // @Autowired
    // private RedisTemplate<Object, Object> redisTemplate;
    //
    // public AuthInterceptor() {
    //
    // }
    //
    // public AuthInterceptor(EmployeeService employeeService, RedisTemplate<Object, Object> redisTemplate) {
    //     this.employeeService = employeeService;
    //     this.redisTemplate = redisTemplate;
    // }
    //
    // @Override
    // public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    //     log.info("拦截类preHandle执行，请求路径为："+request.getRequestURI());
    //     response.setCharacterEncoding("utf-8");
    //
    //     //Object handler是什么:SpringMVC会将请求通过处理器映射器将请求交给匹配的Handler处理，这个handler参数就是描述处理请求的处理器。
    //     //如果不是映射到方法(即-路径下的方法)直接放行
    //     if(!(handler instanceof HandlerMethod)){
    //         return true;
    //     }
    //
    //     //HandlerMethod:封装有关由方法和bean组成的处理程序方法的信息。提供对方法参数、方法返回值、方法注释等的方便访问。
    //     HandlerMethod handlerMethod=(HandlerMethod) handler;
    //     //分开判断，提高性能
    //     Method method = handlerMethod.getMethod();
    //     //检查是否有PassToken注解，有再判断required属性
    //     if (method.isAnnotationPresent(PassToken.class)) {
    //         //进入到PassToken的注解中，查看里面required的值（默认true）
    //         PassToken passToken=method.getAnnotation(PassToken.class);
    //         //如果required为true，该方法不需要认证，return true放行，如果required为false，需要认证，代码往下执行
    //         if(passToken.required()){
    //             return true;
    //         }
    //     }
    //
    //     //获取请求头的token
    //     String token = request.getHeader("Authorization");
    //
    //     //检查是否有EmployeeLoginToken注解，有则需要认证，没有则放行
    //     if (method.isAnnotationPresent(EmployeeLoginToken.class)) {
    //         //如果EmployeeLoginToken注解的required属性为true,则需要认证
    //         if (method.getAnnotation(EmployeeLoginToken.class).required()) {
    //             //如果没携带token，表示当前状态未登陆
    //             if (StrUtil.isEmpty(token)) {
    //                 log.info("未登录，无令牌");
    //                 //如何响应给前端，提示用户未登录要重新登录？？？
    //                 //将错误信息封装为对象后再转换为json格式响应给前端，为什么不能直接return对象
    //                 response.getWriter().write(JSON.toJSONString(Result.error("NOTLOGIN")));
    //                 return false;
    //             }
    //
    //             log.info("**********根据token获取缓存中的信息,解析为实体对象（即登录时在数据库中获取到的员工对象）");
    //             Object obj = redisTemplate.opsForValue().get(TokenConstant.EMPLOYEE_TOKEN_PREFIX + token);
    //             if (Objects.isNull(obj)) {
    //                 log.info("用户名或密码错误");
    //                 response.getWriter().write(JSON.toJSONString(Result.error("登录失败")));
    //                 return false;
    //             }
    //             EmployeeDto employeeDto = JSON.parseObject((String) obj, EmployeeDto.class);
    //
    //             log.info("**********将员工id存入线程，方便获取：id为"+employeeDto.getId());
    //             TokenHolder.setCurrentId(employeeDto.getId());
    //
    //             //验证token，不知是否有必要
    //             boolean verify = false;
    //             try {
    //                 verify = TokenUtil.verify(token);
    //             } catch (JWTVerificationException e) {
    //                 throw new CustomException("401");
    //             }
    //             //令牌验证不通过，拦截
    //             if (!verify) {
    //                 log.info("token认证错误");
    //                 response.getWriter().write(JSON.toJSONString(Result.error("登录失败")));
    //                 return false;
    //             }
    //
    //         }
    //     }
    //
    //     return true;
    // }
}
// public class AuthenticationInterceptor implements HandlerInterceptor {
//
//     @Autowired
//     private EmployeeService employeeService;
//
//     @Override
//     public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
//         String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
//         // 如果不是映射到方法直接通过
//         if(!(object instanceof HandlerMethod)){
//             return true;
//         }
//         HandlerMethod handlerMethod=(HandlerMethod)object;
//         Method method=handlerMethod.getMethod();
//         //检查是否有passtoken注释，有则跳过认证
//         if (method.isAnnotationPresent(PassToken.class)) {
//             PassToken passToken = method.getAnnotation(PassToken.class);
//             if (passToken.required()) {
//                 return true;
//             }
//         }
//         //检查有没有需要用户权限的注解
//         if (method.isAnnotationPresent(EmployeeLoginToken.class)) {
//             EmployeeLoginToken employeeLoginToken = method.getAnnotation(EmployeeLoginToken.class);
//             if (employeeLoginToken.required()) {
//                 // 执行认证
//                 if (token == null) {
//                     throw new RuntimeException("无token，请重新登录");
//                 }
//                 // 获取 token 中的 user id
//                 String userId;
//                 try {
//                     userId = JWT.decode(token).getAudience().get(0);
//                 } catch (JWTDecodeException j) {
//                     throw new RuntimeException("401");
//                 }
//                 Employee employee = employeeService.findUserById();
//                 if (employee == null) {
//                     throw new RuntimeException("用户不存在，请重新登录");
//                 }
//                 // 验证 token
//                 JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(employee.getPassword())).build();
//                 try {
//                     jwtVerifier.verify(token);
//                 } catch (JWTVerificationException e) {
//                     throw new RuntimeException("401");
//                 }
//                 return true;
//             }
//         }
//         return true;
//     }
//
//     @Override
//     public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
//
//     }
//     @Override
//     public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
//
//     }
// }
